#ifndef _SSD1306_C
#define _SSD1306_C

#include "ssd1306.h"

unsigned char *display_mapping;
unsigned char default_gram[GRAM_SIZE];

HAL_StatusTypeDef SSD1306_send_cmd (I2C_HandleTypeDef *hi2c, unsigned char cmd)
{
  unsigned char sending_buffer[2];

  sending_buffer[0] = 0x00;
  sending_buffer[1] = cmd;

  return HAL_I2C_Master_Transmit (hi2c, OLED_CHIP_ADDR, sending_buffer, 2, OLED_CHIP_TIMEOUT);
}

HAL_StatusTypeDef SSD1306_send_data (I2C_HandleTypeDef *hi2c, unsigned char *data, unsigned int data_size)
{
  return HAL_I2C_Mem_Write (hi2c, OLED_CHIP_ADDR, 0x40, 1, data, data_size, OLED_CHIP_TIMEOUT);
}

int SSD1306_Clean ()
{
  for (int i = 0; i < GRAM_SIZE; ++i)
  {
    display_mapping[i] = 0x00;
  }
  
  return 0;
}

HAL_StatusTypeDef SSD1306_Init (I2C_HandleTypeDef *hi2c)
{
  SSD1306_send_cmd(hi2c,0xAE);//关闭显示

  SSD1306_send_cmd(hi2c,0xD5);//设置时钟分频因子,震荡频率
  SSD1306_send_cmd(hi2c,80);  //[3:0],分频因子;[7:4],震荡频率

  SSD1306_send_cmd(hi2c,0xA8);//设置驱动路数
  SSD1306_send_cmd(hi2c,0X3F);//默认0X3F(hi2c,1/64)

  SSD1306_send_cmd(hi2c,0xD3);//设置显示偏移
  SSD1306_send_cmd(hi2c,0X00);//默认为0

  SSD1306_send_cmd(hi2c,0x40);//设置显示开始行 [5:0],行数.

  SSD1306_send_cmd(hi2c,0x8D);//电荷泵设置
  SSD1306_send_cmd(hi2c,0x14);//bit2，开启/关闭

  SSD1306_send_cmd(hi2c,0x20);//设置内存地址模式
  SSD1306_send_cmd(hi2c,0x00);
  
  SSD1306_send_cmd(hi2c,0xA1);//段重定义设置,bit0:0,0->0;1,0->127;
  SSD1306_send_cmd(hi2c,0xC0);
  
  SSD1306_send_cmd(hi2c,0xDA);//设置COM硬件引脚配置
  SSD1306_send_cmd(hi2c,0x12);//[5:4]配置
  
  SSD1306_send_cmd(hi2c,0x81);//对比度设置
  SSD1306_send_cmd(hi2c,0xEF);//1~255;默认0X7F (hi2c,亮度设置,越大越亮)
  
  SSD1306_send_cmd(hi2c,0xD9);//设置预充电周期
  SSD1306_send_cmd(hi2c,0xf1);//[3:0],PHASE 1;[7:4],PHASE 2;
  
  SSD1306_send_cmd(hi2c,0xDB);//设置VCOMH 电压倍率
  SSD1306_send_cmd(hi2c,0x30);//[6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;
  
  SSD1306_send_cmd(hi2c,0xA4);//全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
  
  SSD1306_send_cmd(hi2c,0xA6);//设置显示方式;bit0:1,反相显示;0,正常显示
  
  SSD1306_send_cmd(hi2c,0xAF);//开启显示
  
  display_mapping = default_gram;
  
  return HAL_OK;
}

int SSD1306_ChangeMapping (unsigned char *mapping_array)
{
  display_mapping = mapping_array;
  return 0;
}

HAL_StatusTypeDef SSD1306_UpdateDisplay (I2C_HandleTypeDef *hi2c)
{
    HAL_StatusTypeDef hal_res;
    
    SSD1306_send_cmd (hi2c, 0xb0);
    SSD1306_send_cmd (hi2c, 0x00);
    SSD1306_send_cmd (hi2c, 0x10);
    
    hal_res = SSD1306_send_data (hi2c, display_mapping, GRAM_SIZE);
    
    return hal_res;
}

int SSD1306_WritePoint (int x, int y)
{
  int byte_index;
  int bit_index;
  
  if (x > 127 || x < 0 || y > 63 || y < 0)
  {
    return -1;
  }
  
  bit_index = y % 8;
  byte_index = (y / 8) * 128 + x;
  
  display_mapping[byte_index] |= (1 << bit_index);
  
  return 0;
}

int SSD1306_DrawJX (int x1, int y1, int x2, int y2)
{
  for (int i = x1; i <= x2; ++i)
  {
    SSD1306_WritePoint (i, y1);
    SSD1306_WritePoint (i, y2);
  }
  for (int i = y1; i <= y2; ++i)
  {
    SSD1306_WritePoint (x1, i);
    SSD1306_WritePoint (x2, i);
  }
  
  return 0;
}

int SSD1306_DrawZX (int x1, int y1, int x2, int y2)
{
  double k1 = 1.0 * (y2 - y1) / (x2 - x1);
  int b1 = y1 - k1 * x1;
  
  for (int i = (x1 < x2 ? x1 : x2); i <= (x1 > x2 ? x1 : x2); ++i)
  {
    SSD1306_WritePoint (i, k1 * i + b1);
  }
  
  double k2 = 1.0 * (x2 - x1) / (y2 - y1);
  int b2 = x1 - k2 * y1;
  
  for (int i = (y1 < y2 ? y1 : y2); i <= (y1 > y2 ? y1 : y2); ++i)
  {
    SSD1306_WritePoint (k2 * i + b2, i);
  }
  
  return 0;
}

int SSD1306_DrawFZ (int xb, int yb, unsigned char *fz)
{
  yb *= 2;
  xb = 15 - xb;
  
  for (int i = 0; i < 16; ++i)
  {
    display_mapping[(yb - 1) * 128 + 16 * xb + i] = fz[15 - i];
    display_mapping[yb * 128 + 16 * xb + i] = fz[31 - i];
  }
  
  return 0;
}

#endif
